#ifndef DISK_H
#define DISK_H

#include "comm/types.h"
#include "ipc/mutex.h"
#include "ipc/sem.h"

#define DISK_NAME_SIZE          32
#define PART_NAME_SIZE          32
#define DISK_PRIMARY_PART_CNT   5
#define DISK_CNT                2
#define DISK_PER_CHANNEL        2
#define IOBASE_PRIMARY          0x1F0
#define MBR_PRIMARY_PART_NR     4

// 参考文章：https://wiki.osdev.org/ATA_PIO_Mode
// 磁盘操作端口
#define DISK_DATA(disk)         (disk->port_base + 0)       // 数据寄存器
#define DISK_ERROR(disk)        (disk->port_base + 1)       // 错误寄存器
#define DISK_SECTOR_COUNT(disk) (disk->port_base + 2)       // 扇区数量寄存器
#define DISK_LBA_LOW(disk)      (disk->port_base + 3)       // Sector Number Register / (LBA_LOW)
#define DISK_LBA_MID(disk)      (disk->port_base + 4)       // Cylinder Low Register  / (LBA_MID)
#define DISK_LBA_HIG(disk)      (disk->port_base + 5)       // Cylinder High Register / (LBA_HIG)
#define DISK_DRIVE(disk)        (disk->port_base + 6)       // Drive / Head Register
#define DISK_STATUS(disk)       (disk->port_base + 7)       // 状态寄存器
#define DISK_CMD(disk)          (disk->port_base + 7)       // 命令寄存器

// 磁盘寄存器控制命令
#define DISK_CMD_IDENTIFY       (0xEC)
#define DISK_CMD_READ           (0x24)
#define DISK_CMD_WRITE          (0x34)

// 磁盘寄存器的状态位
#define DISK_STATUS_ERR         (1 << 0)        // 发生错误
#define DISK_STATUS_DRQ         (1 << 3)        // 磁盘控制器就绪，可以写数据或者读取数据
#define DISK_STATUS_DF          (1 << 5)        // 驱动器故障错误
#define DISK_STATUS_BUSY        (1 << 7)        // 磁盘控制器忙

// 0x1F6 寄存器（drive/head）对应位功能如下：
// 0-3 在 bits 24 to 27 of the bolock number.
// 4 驱动号
// 5 默认为1
// 6 设置LBA模式，总位1
// 7 默认为1
#define DISK_DRIVE_BASE         0xE0            // 磁盘drive寄存器的高4位默认值

#pragma pack(1)
// MBR的分区表项类型
typedef struct _part_item_t {
    uint8_t boot_active;                // 分区是否活动(是否是主分区)
	uint8_t start_header;               // 起始header
	uint16_t start_sector : 6;          // 起始扇区
	uint16_t start_cylinder : 10;	    // 起始磁道
	uint8_t system_id;	                // 文件系统类型
	uint8_t end_header;                 // 结束header
	uint16_t end_sector : 6;            // 结束扇区
	uint16_t end_cylinder : 10;         // 结束磁道
	uint32_t relative_sectors;	        // 相对于该驱动器开始的相对扇区数(这个分区在整个磁盘的中的扇区数 == 当前扇区的LBA值)
	uint32_t total_sectors;             // 总的扇区数
} part_item_t;

// 主引导记录，硬盘的前512字节
typedef struct _mbr_t {
    uint8_t code[446];
    part_item_t part_item[MBR_PRIMARY_PART_NR];
    uint8_t boot_sig[2];                        // 0xAA55
} mbr_t;
#pragma pack()

struct _disk_t;
typedef struct _partinfo_t {
    char name[PART_NAME_SIZE];
    struct _disk_t *disk;           // 磁盘分区对所在磁盘的一个反向引用，留作以后使用

    enum {                          // 当前分区管理方式
        FS_INVALID = 0x00,
        FS_FAT16_0 = 0x6,
        FS_FAT16_1 = 0xE,
    } type;

    int start_sector;               // 当前分区的起始扇区号
    int total_sector;               // 当前分区的总共扇区数量

} partinfo_t;

// 描述一个磁盘
typedef struct _disk_t {
    char name[DISK_NAME_SIZE];
    enum {                          // 主/从盘
        DISK_MASTER = (0 << 4),
        DISK_SLAVE = (1 << 4),
    } drive;

    uint16_t port_base;             // 操作当前磁盘的起始寄存器端口地址，方便以后支持次总线上的主、从磁盘

    int sector_size;
    int sector_count;
    partinfo_t partinfo[DISK_PRIMARY_PART_CNT];

    mutex_t *mutex;
    sem_t *op_sem;
} disk_t;

void disk_init(void);

#endif